package com.zh.chat.controller;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.HashMap;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

import org.apache.log4j.Logger;

import com.zh.chat.entity.Friend;
import com.zh.chat.entity.UDPProtocol;
import com.zh.chat.entity.User;
import com.zh.chat.entity.UserInfo;
import com.zh.chat.gui.ChatFrame;
import com.zh.chat.gui.LoginFrame;
import com.zh.chat.gui.MainFrame;
import com.zh.chat.gui.RegistFrame;
import com.zh.chat.gui.UserInfoFrame;
import com.zh.chat.net.FileServer;
import com.zh.chat.service.NetService;
import com.zh.chat.util.FileManager;
import com.zh.chat.util.FileOperationUtil;
import com.zh.chat.util.FileType;



/**
 * 客户端上下文环境，是客户端的控制器 提供界面的流程控制逻辑 MVC中的C 依赖注入：IOC
 * 
 * @author Administrator
 * 
 */
public class ClientContext {
	private Logger log = Logger.getLogger(ClientContext.class);
	private boolean acceptEnable = false;
	private com.zh.chat.entity.UserInfo userInfo;
	private LoginFrame loginFrame;// 默认null,有变量没有对象
	private UserInfoFrame userInfoFrame = null;
	private NetService netService;// 网络服务
	private AcceptThead acceptTh = null;

	// bean属性修改方法，实现了对象注入的功能，将登陆界面对象的引用注入到this.loginFrame.
	// 注意：login()方法以来登陆界面对象，所以要在使用login方法之前调用setLoginFrame方法注入登陆几面对象
	// 如果没有注入登陆界面对象，将发生NullPointerException
	public void setLoginFrame(LoginFrame loginFrame) {
		this.loginFrame = loginFrame;
	}

	public LoginFrame getLoginFrame() {
		return loginFrame;
	}

	public UserInfoFrame getUserInfoFrame() {
		return userInfoFrame;
	}

	public void setUserInfoFrame(UserInfoFrame userInfoFrame) {
		this.userInfoFrame = userInfoFrame;
	}

	public void showUserInfoFrame() {
		if (userInfoFrame == null) {
			userInfoFrame = new UserInfoFrame();
			userInfoFrame.setClientContext(this);
			userInfoFrame.setUserInfo(this.userInfo);
			userInfoFrame.setLocationRelativeTo(null);
		}
		userInfoFrame.setVisible(true);
	}

	public void setNetService(NetService netService) {
		this.netService = netService;
	}

	public NetService getNetService() {
		return netService;
	}

	public com.zh.chat.entity.UserInfo getUserInfo() {
		return userInfo;
	}

	public void setUserInfo(com.zh.chat.entity.UserInfo userInfo) {
		this.userInfo = userInfo;
	}

	/**
	 * 视图属性的设置方法 用于让控制器认识视图
	 * 
	 * @param mianService
	 */
	private MainFrame mainFrame;

	public MainFrame getMainFrame() {
		return mainFrame;
	}

	public void setMainFrame(MainFrame mainFrame) {
		this.mainFrame = mainFrame;
	}

	/**
	 * 登陆方法向服务器发送登陆请求
	 * 
	 * @param id
	 * @param pwd
	 * @param ip
	 * @param port
	 * @param status
	 * @return
	 */
	public void login(Long id, String pwd, String ip, int port, int status) {
		// 将id和密码交给业务逻辑mainService的登陆方法
		netService.login(id, pwd, status);// 发送登陆UDP
	}

	private HashMap<java.lang.Long, ChatFrame> chatFrameMap = new HashMap<java.lang.Long, ChatFrame>();

	public ChatFrame getChatFrame(java.lang.Long id) {
		return chatFrameMap.get(id);
	}

	public void addChatFrame(Long reqId, ChatFrame frame) {
		chatFrameMap.put(reqId, frame);
	}

	/**
	 * 准备聊天窗口
	 * 
	 * @param friend
	 */
	public void readyToChat(Friend friend) {
		ChatFrame existFrame = chatFrameMap.get(friend.getFriendId());
		if (existFrame == null) {
			existFrame = new ChatFrame(friend);
			existFrame.setClientContext(this);
			existFrame.setLocationRelativeTo(null);
			existFrame.setVisible(true);
			existFrame.initLogTextArea();
			chatFrameMap.put(friend.getFriendId(), existFrame);
		}else{
			existFrame.setVisible(true);
		}
	}

	/**
	 * 发送消息给好友
	 * 
	 * @param friend
	 * @param msg
	 */
	public void sendMsgToServer(Friend friend, String msg) {
		UDPProtocol protocol = new UDPProtocol();
		protocol.setCode(UDPProtocol.REQ_SEND_MSG);
		protocol.setTargetId(friend.getFriendId());
		protocol.setRequestId(friend.getSysId());
		protocol.setData(msg);
		protocol.setClazz(msg.getClass().getName());
		getNetService().send(protocol);
	}

	/**
	 * 销毁聊天窗口
	 * 
	 * @param id
	 */
	public void destroyChatFrame(java.lang.Long id) {
		ChatFrame chatFrame = chatFrameMap.get(id);
		chatFrame.setVisible(false);
		chatFrameMap.remove(id);
		chatFrame = null;
	}
	
	/**
	 * 注册用户
	 * @param userInfo2
	 */
	public void registUser(User user) {
		UDPProtocol protocol = new UDPProtocol();
		{
			protocol.setCode(UDPProtocol.REQ_REGIST);
			protocol.setData(user);
			protocol.setClazz(user.getClass().getName());
			getNetService().send(protocol);
		}
	}
	private RegistFrame registFrame = null;
	/**
	 * 获取注册框体
	 * @return
	 */
	public RegistFrame getRegistFrame() {
		return registFrame;
	}
	
	public void showRegistFrame() {
		registFrame = new RegistFrame();
		registFrame.setClientContext(this);
		registFrame.setVisible(true);
	}
	public void closeRegistFrame() {
		registFrame.setVisible(false);
	}
	
	/**
	 * 请求服务器修改用户资料
	 */
	public void modifyUser(UserInfo info) {
		java.lang.Long id = info.getSysId();
		User user = info.getUser();
		UDPProtocol protocol = new UDPProtocol();
		{
			protocol.setRequestId(id);
			protocol.setCode(UDPProtocol.REQ_MODIFY_MATERIAL);
			protocol.setData(user);
			protocol.setClazz(user.getClass().getName());
			getNetService().send(protocol);
		}
		userInfo = info;
	}

	/**
	 * 发送请求，使用TCP发送头像文件到服务器
	 */
	public void modifySculpture(User user, String oldPath) {
		UDPProtocol protocol = new UDPProtocol();
		protocol.setRequestId(user.getSysId());
		protocol.setCode(UDPProtocol.REQ_MODIFY_PROFILE);
		ServerSocket server = netService.getTcpDTO().getFreeSocket();// 获取空闲的TCP端口
		String fileInfo = FileType.SCULPTURE + ":" + server.getLocalPort()
				+ ":" + user.getImage();
		protocol.setClazz(fileInfo.getClass().getName());
		protocol.setData(fileInfo);
		String path = FileOperationUtil.getFilePath(FileType.SCULPTURE,user.getSysId(), user.getImage());
		try {
			new FileServer(server, path, this, protocol);// 开始监听请求
			log.info("头像发送成功" + path);
			// 删除掉原来的头像
			FileManager.delFile(oldPath);
			mainFrame.updateUserView(user);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void changeStatus(int status) {
		if (status == 5) {
			// JOptionPane.showMessageDialog(mainFrame, "您已经离线，请重新登陆", "重新登陆",
			// JOptionPane.WARNING_MESSAGE);
			// loginFrame.setVisible(true);
			// mainFrame.setVisible(false);
			// mainFrame.reset();
			logout();
		} else {
			UDPProtocol protocol = new UDPProtocol();
			protocol.setRequestId(userInfo.getSysId());
			protocol.setTargetId(0L);
			protocol.setCode(UDPProtocol.REQ_CHANGE_STATUS);
			protocol.setClazz(new Integer(status).getClass().getName());
			protocol.setData(status);
			netService.send(protocol);// 发送状态改变请求
		}
	}

	/**
	 * 专供Main方法调用，用来启动UDP命令接收线程
	 */
	public void startUDPReciver() {
		if (!acceptEnable) {// 为保证acceptEnable只执行一次
			acceptTh = new AcceptThead(this);
			acceptTh.start();
			acceptEnable = true;
		}
	}

	public void stop() {
		if (acceptTh != null) {
			acceptTh.shutDownThread();// 结束接收
		}
		netService.close();
		System.exit(0);
	}

	/**
	 * 接收服务器指令的进程
	 * 
	 * @author Toms
	 */
	class AcceptThead extends Thread {
		ClientContext context = null;
		boolean running = true;

		public AcceptThead(ClientContext clientContext) {
			this.context = clientContext;
		}

		public synchronized void shutDownThread() {
			running = false;
		}

		public synchronized boolean isShutDown() {
			return running;
		}

		@Override
		public void run() {
			while (running) {
				UDPProtocol protocol = netService.recive();
				if (protocol.getCode() == UDPProtocol.RESP_LOGOUT
						&& (Boolean) protocol.getData()) {
					running = false;
				}
				Thread process = new Thread(
						new AnalyzeThread(protocol, context));
				process.start();
			}
			System.out.println("UDP命令接收线程已经结束");
		}
	}

	public void writeChatLog(Friend friend, UDPProtocol protocol) {
		try {
			FileOperationUtil.appendChatLog(friend, userInfo, protocol);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public String readChatLog(java.lang.Long friendId) {
		String path = FileOperationUtil.getFilePath(FileType.CHATLOG,
				userInfo.getSysId(), friendId + ".log");
		String content = null;
		try {
			content = FileOperationUtil.getChatLog(path);
		} catch (FileNotFoundException e) {
			return content;
		}
		return content;
	}

	/**
	 * 准备语言聊天，发送请求给服务器
	 */
	public void readyVoice(java.lang.Long reqId, java.lang.Long tarId) {
		netService.readyVoice(reqId, tarId);
	}
	
	public void logout() {
		UDPProtocol prot = new UDPProtocol();
		prot.setCode(UDPProtocol.REQ_LOGOUT);
		if (userInfo == null) {
			prot.setRequestId(loginFrame.getUserId());
		} else {
			prot.setRequestId(userInfo.getSysId());
		}
		prot.setTargetId(0L);
		netService.send(prot);
	}

	/**
	 * 当某个按钮准备关闭时，执行关闭流程
	 * 
	 * @param frame
	 *            点击关闭窗口的按钮的那个窗口 1：显示确认对话框 2：若用户确定退出，先将当前窗口隐藏 3：停止java虚拟机进程
	 */
	public boolean exit(JFrame source) {
		// 显示确认对话框
		int val = JOptionPane.showConfirmDialog(source, "确实想离开吗？", "退出",
				JOptionPane.YES_NO_OPTION);
		if (val == JOptionPane.YES_OPTION) {
			source.setVisible(false);
			return true;
		}
		return false;
	}

	/**
	 * 清空用户资料框,释放内存
	 */
	public void closeUserInfoFrame() {
		userInfoFrame = null;
	}
}